//
//  MainViewModel.swift
//  TomatoClock
//
//  Created by DaleGuo on 2023/11/21.
//

import Combine
import CoreData
import Foundation

class HomeViewModel: ObservableObject {
    var viewContext = PersistentController.shared.viewContext
    
    @Published var allTomatoes: [TomatoEntity] = []
    @Published var chartData: [Date: Int] = [:]
    @Published var weekData: [TomatoEntity] = []
    
    private var cancelables = Set<AnyCancellable>() // 当不需要主动cancel时，就将其存入set中
    
    init() {
        getAllTomatoes()
        addSubscriber()
    }
    
    func getAllTomatoes() {
        let request = NSFetchRequest<TomatoEntity>(entityName: "TomatoEntity")
        request.sortDescriptors = [NSSortDescriptor(keyPath: \TomatoEntity.created_time_, ascending: false)]

        do {
            allTomatoes = try viewContext.fetch(request)

        } catch {
            print("Error fetching portfolio entity: \(error)")
        }
    }
    
    func addSubscriber() {
        
        $allTomatoes
            .map { allTomatoes in
                self.filterWeekTomato(tomatos: allTomatoes)
            }
            .sink { filteredTomatos in
                self.weekData = filteredTomatos
            }
            .store(in: &cancelables)
        
        $weekData
            .map { weekData in
                
                var dict = self.getWeekDict()
                
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "yyyy-MM-dd"
                
                let calendar = Calendar.current
                // 循环weekTomatos, 并往dict添值
                for item in weekData {
                    let dateComp = calendar.dateComponents([.year, .month, .day], from: item.created_time_!)
                    let date = Calendar.current.date(from: dateComp)
                    print(date!.formatted())
                    dict[date!] = dict[date!]! + Int(item.tomato_num_)
                }
                return dict
            }
            .sink { ss in
                self.chartData = ss
            }
            .store(in: &cancelables)
    }
    
    private func getWeekDict() -> [Date: Int] {
        // 生成最近一周的字典
        var dict = [Date: Int]()
        let calendar = Calendar.current
        for dayOffset in -6 ... 0 {
            if let date = calendar.date(byAdding: .day, value: dayOffset, to: Date()) {
                let dateComp = calendar.dateComponents([.year, .month, .day], from: date)
                let date = Calendar.current.date(from: dateComp)
                dict[date!] = 0
            }
        }
        
        return dict
    }
    
    private func filterWeekTomato(tomatos: [TomatoEntity]) -> [TomatoEntity] {
        return tomatos.filter { tomato in
            tomato.created_time_!.isWithinLastSevenDays()
        }
    }
    
    func addItem(clock_time: Int) {
        // 实例化一条 Item 实体的数据
        let newTomato = TomatoEntity(context: viewContext)
        newTomato.created_time_ = Date()
        newTomato.clock_time_ = Int32(clock_time)
//        newTomato.tomato_num_ = Int32(clock_time / 25)
        newTomato.tomato_num_ = 1 // 测试
        
        do {
            try viewContext.save()
            
            // 刷新数据
            getAllTomatoes()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
    
    private func getLastWeekDays() -> [Date] {
        let dateComponents = Calendar(identifier: .gregorian).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date())
        let startOfWeek = Calendar(identifier: .gregorian).date(from: dateComponents)!
        let startOfWeekNoon = Calendar(identifier: .gregorian).date(bySettingHour: 12, minute: 0, second: 0, of: startOfWeek)!
        let weekDays = (0 ... 6).map { Calendar(identifier: .gregorian).date(byAdding: .day, value: $0, to: startOfWeekNoon)! }
        
        return weekDays
    }
}

extension Date {
    func isWithinLastSevenDays() -> Bool {
        let calendar = Calendar.current
        let now = Date()
        let sevenDaysAgo = calendar.date(byAdding: .day, value: -7, to: now)
        return self >= (sevenDaysAgo ?? now)
    }
}
